package com.ce.server.config.security;

import com.ce.server.pojo.Admin;
import com.ce.server.pojo.Student;
import com.ce.server.service.IAdminService;
import com.ce.server.service.IStudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.StringUtils;

/**
 * @DATE: 2021/11/14 16:49
 * @Author: 小爽帅到拖网速
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private IAdminService adminService;
  @Autowired
  private IStudentService studentService;

  @Autowired
  RestAccessDeniedHandler accessDeniedHandler;
  @Autowired
  RestAuthenticationEntryPoint authenticationEntryPoint;
  @Autowired
  private CustomFilter customFilter;
  @Autowired
  private CustomUrlDecisionManager customUrlDecisionManager;

  @Value("${type.admin}")
  private String admin_type;

  @Value("${type.student}")
  private String student_type;

  /**
   * 认证管理器
   *
   * @param auth
   * @throws Exception
   */
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
  }

  /**
   * http管理器
   *
   * @param http
   * @throws Exception
   */
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http // 使用jwt不需要防止跨站伪造请求攻击
            .csrf()
            .disable()
            // 基于token不需要session
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .anyRequest().authenticated() // 除了WebSecurity放行的路径其他的都要拦截
            // 动态权限的配置
            .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
              @Override
              public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                o.setSecurityMetadataSource(customFilter);
                o.setAccessDecisionManager(customUrlDecisionManager);
                return o;
              }
            })
            .and()
            .headers()
            .cacheControl(); // 禁用缓存
    // jwt登录授权拦截器
    http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    http.exceptionHandling()
            // 未授权
            .accessDeniedHandler(accessDeniedHandler)
            // 未登录
            .authenticationEntryPoint(authenticationEntryPoint);
  }

  /**
   * 安全路径放行
   *
   * @param web
   * @throws Exception
   */
  @Override
  public void configure(WebSecurity web) throws Exception {
    // 放行静态资源
    web.ignoring().antMatchers(
            "/login",
            "/logout",
            "/css/**",
            "/js/**",
            "/index.html",
            "/favicon.ico",
            "/doc.html",
            "/webjars/**",
            "/swagger-resources/**",
            "/v2/api-docs/**",
            "/captcha"
    );
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }


  @Override
  @Bean
  public UserDetailsService userDetailsService() {

    return account_no -> {

      if (StringUtils.startsWithIgnoreCase(account_no, admin_type)) {
        Admin admin = adminService.getAdminByWno(account_no);
        if (admin != null) {
          admin.setRoles(adminService.getRoles(admin.getWno()));
          return admin;
        } else throw new UsernameNotFoundException("用户名或密码不正确");
      } else if (StringUtils.startsWithIgnoreCase(account_no, student_type)) {
        Student student = studentService.getStudentBySno(account_no);
        if (student != null) {
          student.setRoles(studentService.getRoleBySno(student.getSno()));
          return student;
        } else throw new UsernameNotFoundException("用户名或密码不正确");
      } else throw new BadCredentialsException("没有添加用户账号标识前缀，你是在恶意攻击吗？");
    };
  }

  @Bean
  public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
    return new JwtAuthenticationTokenFilter();
  }
}
